package fem2.observer;

import inf.jlinalg.IVector;

import java.io.IOException;
import java.util.ArrayList;

import fem2.Debugger;
import fem2.Element;
import fem2.Model;
import fem2.element.crack_sda.SDAElement;

/**
 * Crack observer for SDAElement
 * 
 * @author hbui
 * 
 */
public class GidCrackObserver2 extends GidStructuralObserver {

	public GidCrackObserver2(Model m, TimeStepObserver o, String projectDir, String projectName) {
		super(m, o, projectDir, projectName);
		validateModel(this.m);
	}

	public GidCrackObserver2(Model m, TimeStepObserver o, String projectDir, String projectName,
			String fileName) {
		super(m, o, projectDir, projectName, fileName);
		// validateModel(this.m);
	}

	private void validateModel(Model m) {
		if (!(m.getElement(0) instanceof SDAElement)) {
			Debugger.error(this.getClass().getName() + "only support for model contains SDAElement");
		}
	}

	@Override
	public void fireStarted() {
	}

	@Override
	public void fireTimeStepStarted() {
	}

	@Override
	public void fireIterationStarted() {
	}

	@Override
	public void fireIterationFinished() {
	}

	@Override
	public void fireTimeStepFinished() {
		int ne = m.countElements();

		/*
		 * gid section. enabled when gidpost!=null
		 */
		if (gidPost != null) {
			for (String elemType : m.getElementTypes()) {
				ArrayList<Integer> elemIds = new ArrayList<Integer>();
				ArrayList<Boolean> isCrackList = new ArrayList<Boolean>();
				ArrayList<IVector> xiList = new ArrayList<IVector>();
				int nxi = 0;
				for (int i = 0; i < ne; i++) {
					Element e = m.getElement(i);
					if (e.getElemType().equals(elemType)) {
						elemIds.add(e.getId());
						if (e instanceof SDAElement) {
							SDAElement ce = (SDAElement) e;
							if (ce.isCracked()) {
								int tmp = ce.getCrackOpeningParameter().getSize();
								if (tmp > nxi)
									nxi = tmp;
								xiList.add(ce.getCrackOpeningParameter());
								isCrackList.add(true);
							} else {
								xiList.add(null);
								isCrackList.add(false);
							}
						} else if (e instanceof fem2.element.crack_sda2.SDAElement) {
							fem2.element.crack_sda2.SDAElement ce = (fem2.element.crack_sda2.SDAElement) e;
							if (ce.isCracked()) {
								int tmp = ce.getCrackOpeningParameter().getSize();
								if (tmp > nxi)
									nxi = tmp;
								xiList.add(ce.getCrackOpeningParameter());
								isCrackList.add(true);
							} else {
								xiList.add(null);
								isCrackList.add(false);
							}
						}

						else {
							xiList.add(null);
							isCrackList.add(false);
						}

					}
				}
				/*
				 * write block of values for isCrack
				 */
				String isCrackedVarName = "IS_CRACKED";
				String xiVarName = "CRACK_OPENING_PARAMETER";

				double timeStep = timeStepObserver.getCurrentTimeStep();

				int[] elementIds = new int[elemIds.size()];
				double[][] isCrackValues = new double[elemIds.size()][1];
				double[][][] xiValues = new double[nxi][elemIds.size()][1];
				for (int i = 0; i < elemIds.size(); i++) {
					elementIds[i] = elemIds.get(i);
					isCrackValues[i][0] = isCrackList.get(i) ? 1 : 0;
					if (xiList.get(i) == null) {
						// for (int j = 0; j < nxi; j++) {
						// xiValues[j][i][0] = 0;
						// }
					} else if (xiList.get(i).getSize() < nxi) {
						for (int j = 0; j < xiList.get(i).getSize(); j++) {
							xiValues[j][i][0] = 0;
						}
					} else {
						for (int j = 0; j < nxi; j++) {
							xiValues[j][i][0] = xiList.get(i).get(j);
						}
					}
				}
				try {
					gidPost.writeMesh(m, timeStep);
					String groupName = "is_cracked_gp_" + elemType;
					gidPost.writeGausspointScalarResult(isCrackedVarName, groupName, elemType,
							elementIds, isCrackValues, timeStep);
					for (int i = 0; i < nxi; i++) {
						groupName = "XI" + (i + 1) + "_gp_" + elemType;
						gidPost.writeGausspointScalarResult(xiVarName, groupName, elemType,
								elementIds, xiValues[i], timeStep);
					}
				} catch (IOException e) {
					throw new Error("Write failed: " + e.getMessage());
				}
			}
		}
	}

	@Override
	public void fireFinished() {
	}

}
